package com.hanock.sm.fork2d;

import javax.microedition.khronos.opengles.GL10;

import android.graphics.RectF;


/**
 * 
 * @author hanockka
 *
 * scale, rotate, translate are deprecated
 */
public class ScrollPanel extends Node {

	private static final float SPEED_DOWN_PER_SEC = 1300;
	private static final float SPEED_MAX = 2400;
	private static final float RECOVER_SPEED = 500;
	private static final float ADDITIONAL_TY = 100;
	
	private RectF rect;
	private boolean down;
	
	private boolean scrollHorizontal;
	private boolean scrollVertical;
	
	private float sensitivity;
	
	private float touchX;
	private float touchY;
	private float preX;
	private float preY;
	
	private float scrollVX; // per sec
	private float scrollVY; // per sec
	
	private float minTY;
	private float maxTY;
	private float minTX;
	private float maxTX;
	
	
	public ScrollPanel() {
		rect = new RectF();
		down = false;
		
		minTY = 0;
		maxTY = 0;
		
		minTX = 0;
		maxTX = 0;
		
		sensitivity = 1;
	}
	
	@Override
	public void visit(Canvas canvas) {
		
		getDesRect(rect);
		
		ViewportInfo viewportInfo = canvas.getViewportInfo();
		
		float sw = 1f*viewportInfo.width/viewportInfo.sceneWidth;
		float sh = 1f*viewportInfo.height/viewportInfo.sceneHeight;
		float left = viewportInfo.left + rect.left*sw;
		float bottom = viewportInfo.bottom + rect.bottom*sh;
		float width = rect.width()*sw;
		float height = Math.abs(rect.height())*sh;
		
		GL10 gl = canvas.getGL();
		gl.glEnable(GL10.GL_SCISSOR_TEST);
		gl.glScissor((int)left, (int)bottom, (int)width, (int)height);
		
		super.visit(canvas);
		
		gl.glDisable(GL10.GL_SCISSOR_TEST);
	}
	
	@Override
	public boolean visit(float x, float y, TouchMode mode) {
		
		if (!isEnabled() || !isTouchable())
			return false;
		
		boolean b = false;
		float x2 = x - getTranslateX();
		float y2 = y - getTranslateY();
		
		for (int i = childList.size() - 1; i >= 0; i--){
			b = childList.get(i).visit(x2, y2, mode);
			if (b)
				return true;
		}
		
		b = onTouch(x, y, mode);
		if (b)
			return true;
		
		return false;
	}
	
	@Override
	public void progress(int elapsed) {
		super.progress(elapsed);
		
		float tx = getTranslateX();
		float ty = getTranslateY();
		
		if (down){
			if (scrollHorizontal){
				scrollVX = 0.4f*scrollVX + 0.6f*sensitivity*(touchX - preX)/(elapsed/1000f);
				preX = touchX;
				
				if (Math.abs(scrollVX) > SPEED_MAX){
					scrollVX = (scrollVX > 0) ? SPEED_MAX: -SPEED_MAX;
				}
			}
			
			if (scrollVertical){
				scrollVY = 0.4f*scrollVY + 0.6f*sensitivity*(touchY - preY)/(elapsed/1000f);
				preY = touchY;
				
				if (Math.abs(scrollVY) > SPEED_MAX){
					scrollVY = (scrollVY > 0) ? SPEED_MAX: -SPEED_MAX;
				}
			}
		}
		else {
			
			if (scrollVertical){
				
				if (ty < minTY){
					scrollVY = 0;
					
					float dy = RECOVER_SPEED*elapsed/1000f;
					float ty2 = ty + dy;
					
					if (ty2 > minTY)
						ty2 = minTY;
					
					setTranslateY(ty2);
				}
				else if (ty > maxTY){
					
					scrollVY = 0;
					
					float dy = -RECOVER_SPEED*elapsed/1000f;
					float ty2 = ty + dy;
					
					if (ty2 < maxTY)
						ty2 = maxTY;
					
					setTranslateY(ty2);
				}
				else if (scrollVY != 0){
					float dy = scrollVY*elapsed/1000f;
					scroll(0, dy);
					
					if (scrollVY > 0){
						scrollVY = scrollVY - SPEED_DOWN_PER_SEC*elapsed/1000f;
						
						if (scrollVY < 0)
							scrollVY = 0;
					}
					else{
						scrollVY = scrollVY + SPEED_DOWN_PER_SEC*elapsed/1000f;
						
						if (scrollVY > 0)
							scrollVY = 0;
					}
				}
			}
			
			
			
			if (scrollHorizontal){
				
				if (tx < minTX){
					scrollVX = 0;
					
					float dx = RECOVER_SPEED*elapsed/1000f;
					float tx2 = tx + dx;
					
					if (tx2 > minTX)
						tx2 = minTX;
					
					setTranslateX(tx2);
				}
				else if (tx > maxTX){
					
					scrollVX = 0;
					
					float dx = -RECOVER_SPEED*elapsed/1000f;
					float tx2 = tx + dx;
					
					if (tx2 < maxTX)
						tx2 = maxTX;
					
					setTranslateX(tx2);
				}
				else if (scrollVX != 0){
					float dx = scrollVX*elapsed/1000f;
					scroll(dx, 0);
					
					if (scrollVX > 0){
						scrollVX = scrollVX - SPEED_DOWN_PER_SEC*elapsed/1000f;
						
						if (scrollVX < 0)
							scrollVX = 0;
					}
					else{
						scrollVX = scrollVX + SPEED_DOWN_PER_SEC*elapsed/1000f;
						
						if (scrollVX > 0)
							scrollVX = 0;
					}
				}
			}
		}
	}
	
	@Override
	protected boolean onTouch(float x, float y, TouchMode mode) {
		
		super.onTouch(x, y, mode);
		
		switch (mode){
		
		case DOWN:
			return onTouchDown(x, y);
			
		case UP:
			return onTouchUp(x, y);
			
		case MOVE:
			return onTouchMove(x, y);
			
		default:
			return false;
		}
	}
	
	public boolean onTouchMove(float x, float y) {
		
		if (!down)
			return false;
		
		if (isInTouchRect(x, y)){
			
			float dx = (x - touchX)*sensitivity;
			float dy = (y - touchY)*sensitivity;
			
			scroll(dx, dy);
			
			touchX = x;
			touchY = y;
			return true;
		}
		else{
			down = false;
			return false;
		}
	}
	
	public boolean onTouchDown(float x, float y) {
		
		if (down){
			down = false;
		}
		
		if (isInTouchRect(x, y)){
			down = true;
			
			touchX = x;
			touchY = y;
			
			preX = x;
			preY = y;
			scrollVY = 0;
			scrollVX = 0;
			
			return true;
		}
		else{
			return false;
		}
	}
	
	public boolean onTouchUp(float x, float y) {
		down = false;
		return false;
	}
	
	private void scroll(float dx, float dy){
		
		if (scrollHorizontal){
			float tx = getTranslateX() + dx;
			
			if (tx < minTX)
				tx = minTX;
			
			if (tx > maxTX)
				tx = maxTX;
			
			setTranslateX(tx);
		}
		
		if (scrollVertical){
			float ty = getTranslateY() + dy;
			
			if (ty < minTY - ADDITIONAL_TY)
				ty = minTY - ADDITIONAL_TY;
			
			if (ty > maxTY + ADDITIONAL_TY)
				ty = maxTY + ADDITIONAL_TY;
			
			setTranslateY(ty);
		}
	}
	
	private boolean isInTouchRect(float x, float y){
		
		getDesRect(rect);

		return MathUtil.contains(rect, x, y);
	}

	public void setMinTY(float minTY) {
		this.minTY = minTY;
	}
	
	public void setMaxTY(float maxTY) {
		this.maxTY = maxTY;
	}

	public void setMinTX(float minTX) {
		this.minTX = minTX;
	}
	
	public void setMaxTX(float maxTX) {
		this.maxTX = maxTX;
	}

	public boolean isScrollHorizontal() {
		return scrollHorizontal;
	}
	
	public void setScrollHorizontal(boolean scrollHorizontal) {
		this.scrollHorizontal = scrollHorizontal;
	}
	
	public boolean isScrollVertical() {
		return scrollVertical;
	}
	
	public void setScrollVertical(boolean scrollVertical) {
		this.scrollVertical = scrollVertical;
	}

	public void setSensitivity(float sensitivity) {
		this.sensitivity = sensitivity;
	}
}
























